
`include "common_header.verilog"

//  *************************************************************************
//  File : top_crcrm_64
//  *************************************************************************
//  This program is controlled by a written license agreement.
//  Unauthorized reproduction or use is expressly prohibited.
//  Copyright (c) 2014 MorethanIP
//  Muenchner Strasse 199, 85757 Karlsfeld, Germany
//  info@morethanip.com
//  http://www.morethanip.com
//  *************************************************************************
//  Designed by : Thomas Schrobenhauser
//  info@morethanip.com
//  *************************************************************************
//  Description : CRC Removal on Receive for 64-bit Datapath
//  Version     : $Id: top_crcrm_64.v,v 1.4 2016/06/27 07:51:08 dp Exp $
//  *************************************************************************

module top_crcrm_64 (
   reset_rxclk,
   rx_clk,
   rx_data_ff,
   rx_sop_ff,
   rx_eop_ff,
   rx_mod_ff,
   rx_wren_ff,
   rx_dval_ff,
   rx_afull_ff,
   rx_empty_st_ff,
   rx_preamble_ff,
   rx_stat_wren_ff,
   rx_stat_data_ff,
   rx_data_mac,
   rx_sop_mac,
   rx_eop_mac,
   rx_mod_mac,
   rx_wren_mac,
   rx_dval_mac,
   rx_afull_mac,
   rx_empty_st_mac,
   rx_preamble_mac,
   rx_stat_wren_mac,
   rx_stat_data_mac,
   crc_fwd
   );
parameter       RX_STAT_DAT_WIDTH_64 = 25;

input   reset_rxclk;                            //  Active High reset for rx_clk domain
input   rx_clk;                                 //  XLGMII Receive clock
output  [63:0] rx_data_ff;                      //  Receive Data to FIFO
output  rx_sop_ff;                              //  Receive Start of Packet
output  rx_eop_ff;                              //  Receive End of Packet
output  [2:0] rx_mod_ff;                        //  Receive last word modulo
output  rx_wren_ff;                             //  Receive Data FIFO write enable
output  rx_dval_ff;                             //  Receive Data valid
input   rx_afull_ff;                            //  Receive Data FIFO almost full
input   rx_empty_st_ff;                         //  RX FIFO empty (data+status)
output  [55:0] rx_preamble_ff;                  //  Receive frame preamble (stable from sop)
output  rx_stat_wren_ff;                        //  Receive Status FIFO write enable
output  [RX_STAT_DAT_WIDTH_64-1:0] rx_stat_data_ff;     //  Receive Frame Status & Error indications
input   [63:0] rx_data_mac;                     //  Receive Data to FIFO
input   rx_sop_mac;                             //  Receive Start of Packet
input   rx_eop_mac;                             //  Receive End of Packet
input   [2:0] rx_mod_mac;                       //  Receive last word modulo
input   rx_wren_mac;                            //  Receive Data FIFO write enable
input   rx_dval_mac;                            //  Receive Data valid
output  rx_afull_mac;                           //  Receive Data FIFO almost full
output  rx_empty_st_mac;                        //  RX FIFO empty (data+status)
input   [55:0] rx_preamble_mac;                 //  Receive frame preamble (stable from sop)
input   rx_stat_wren_mac;                       //  Receive Status FIFO write enable
input   [RX_STAT_DAT_WIDTH_64-1:0] rx_stat_data_mac;    //  Receive Frame Status & Error indications
input   crc_fwd;                                //  Forward Frames with CRC to Application

wire    [63:0] rx_data_ff;
wire    rx_sop_ff;
wire    rx_eop_ff;
wire    [2:0] rx_mod_ff;
wire    rx_wren_ff;
wire    rx_dval_ff;
wire    [55:0] rx_preamble_ff;
wire    rx_stat_wren_ff;
wire    [RX_STAT_DAT_WIDTH_64-1:0] rx_stat_data_ff;
wire    rx_afull_mac;
wire    rx_empty_st_mac;

wire    crc_fwd_r;
reg     [63:0] rx_data_r;
reg     rx_sop_r;
reg     rx_eop_r;
reg     [2:0] rx_mod_r;
reg     rx_wren_r;
reg     [55:0] rx_preamble_r;
reg     rx_stat_wren_r;
reg     [RX_STAT_DAT_WIDTH_64-1:0] rx_stat_data_r;
wire    [63:0] rx_data_crc;
wire    rx_sop_crc;
wire    rx_eop_crc;
wire    [2:0] rx_mod_crc;
wire    rx_wren_crc;
wire    [55:0] rx_preamble_crc;
wire    rx_stat_wren_crc;
wire    [RX_STAT_DAT_WIDTH_64-1:0] rx_stat_data_crc;
wire    eop_adv;


// Clock domain crossings
// ----------------------
mtip_xsync #(1) U_RXSYNC (
          .data_in(crc_fwd),
          .reset(reset_rxclk),
          .clk(rx_clk),
          .data_s(crc_fwd_r));


// Datapath register
// -----------------
always @(posedge rx_clk or posedge reset_rxclk)
   begin
   if (reset_rxclk == 1'b 1)
      begin
      rx_data_r      <= {64{1'b 0}};
      rx_sop_r       <= 1'b 0;
      rx_eop_r       <= 1'b 0;
      rx_mod_r       <= {3{1'b 0}};
      rx_wren_r      <= 1'b 0;
      rx_preamble_r  <= {56{1'b 0}};
      rx_stat_wren_r <= 1'b 0;
      rx_stat_data_r <= {RX_STAT_DAT_WIDTH_64{1'b 0}};
      end
   else
      begin
      // dval
      if (rx_dval_mac == 1'b 1 & rx_wren_mac == 1'b 1)
         begin
         rx_data_r      <= rx_data_mac;
         rx_sop_r       <= rx_sop_mac;
         rx_mod_r       <= {~rx_mod_mac[2], rx_mod_mac[1:0]};
         rx_preamble_r  <= rx_preamble_mac;
         rx_stat_data_r <= rx_stat_data_mac;
         end

      if (rx_dval_mac == 1'b 1 & (rx_wren_mac == 1'b 1 | rx_eop_r == 1'b 1))
         begin
         rx_eop_r       <= rx_eop_mac & ~eop_adv;
         rx_wren_r      <= rx_wren_mac & ~eop_adv;
         rx_stat_wren_r <= rx_stat_wren_mac & ~eop_adv;
         end
      end
   end


// CRC Removal
// -----------
assign rx_data_crc     = rx_data_r;
assign rx_sop_crc      = rx_sop_r;
assign rx_preamble_crc = rx_preamble_r;

assign eop_adv = rx_eop_mac == 1'b 1 & rx_wren_mac == 1'b 1 & rx_sop_r == 1'b 0 &   // avoid single-cycle frames
                 (rx_mod_mac == 3'b 100 |
                 (rx_mod_mac[2] == 1'b 0 & rx_mod_mac[1:0] != 2'b 00)) ? 1'b 1 : 1'b 0;

assign rx_eop_crc       = rx_eop_r | eop_adv;
assign rx_mod_crc       = eop_adv == 1'b 0 ? rx_mod_r : {~rx_mod_mac[2], rx_mod_mac[1:0]};
assign rx_stat_data_crc = eop_adv == 1'b 0 ? rx_stat_data_r : rx_stat_data_mac;

// write enables gated with dval (clock enable)
assign rx_wren_crc      = ((rx_wren_r & (rx_wren_mac | rx_eop_r)) | (rx_wren_mac & eop_adv)) & rx_dval_mac;
assign rx_stat_wren_crc = ((rx_stat_wren_r & (rx_wren_mac | rx_eop_r)) | (rx_stat_wren_mac & eop_adv)) & rx_dval_mac;


// Output Mux
// ----------
assign rx_data_ff      = crc_fwd_r == 1'b 1 ? rx_data_mac      : rx_data_crc;
assign rx_sop_ff       = crc_fwd_r == 1'b 1 ? rx_sop_mac       : rx_sop_crc;
assign rx_eop_ff       = crc_fwd_r == 1'b 1 ? rx_eop_mac       : rx_eop_crc;
assign rx_mod_ff       = crc_fwd_r == 1'b 1 ? rx_mod_mac       : rx_mod_crc;
assign rx_wren_ff      = crc_fwd_r == 1'b 1 ? rx_wren_mac      : rx_wren_crc;
assign rx_preamble_ff  = crc_fwd_r == 1'b 1 ? rx_preamble_mac  : rx_preamble_crc;
assign rx_stat_wren_ff = crc_fwd_r == 1'b 1 ? rx_stat_wren_mac : rx_stat_wren_crc;
assign rx_stat_data_ff = crc_fwd_r == 1'b 1 ? rx_stat_data_mac : rx_stat_data_crc;

// dval ("true" clock enable)
assign rx_dval_ff = rx_dval_mac;

assign rx_afull_mac    = rx_afull_ff;
assign rx_empty_st_mac = rx_empty_st_ff;


endmodule // module top_crcrm_64
